using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Xml;
using System.Diagnostics;

namespace Notify2
{
    public partial class NotifierTrayHiddenForm : Form
    {
        int fullcount = 0;
        int lastSeenCount = 0;
        DateTime LastSeen
        {
            get
            {
                return Properties.Settings.Default.LastSeen;
            }
            set
            {
                Properties.Settings.Default.LastSeen = value;
            }
        }
        DateTime lastPopup = DateTime.MinValue;

        public NotifierTrayHiddenForm()
        {
            InitializeComponent();
        }

        private void checkMailTimer_Tick(object sender, EventArgs e)
        {
            CheckMail();
        }

        private void NotifierTrayHiddenForm_Shown(object sender, EventArgs e)
        {
            string[] args = Environment.GetCommandLineArgs();
            if (args.Length == 1) //No arguments
            {
                if (DialogResult.OK == Program.OptionsForm.ShowDialog())
                {
                    CheckMail();
                    checkMailTimer.Enabled = true;
                }
            }
            else if (args[1].ToLower() == "/tray")
            {
                EnsureLoginPwd();
                CheckMail();
                checkMailTimer.Enabled = true;
            }
            else if (args[1].ToLower() == "/send")
            {
                EnsureLoginPwd();
                Program.SendMailForm.Show();
            }
        }

        private void EnsureLoginPwd()
        {
            while (Program.OptionsForm.loginTextBox.Text == ""
                || Program.OptionsForm.pwdTextBox.Text == "")
            {
                if (DialogResult.Cancel == Program.OptionsForm.ShowDialog())
                    break;
            }

            // This method do nto exits until login & pwd or cancel.
            // cancel button on OptionsForm just exits the application.
        }



        private void NotifierTrayHiddenForm_Load(object sender, EventArgs e)
        {
            this.Visible = false;
            Program.OptionsForm = new OptionsForm();
            Program.SendMailForm = new SendMailForm();
            if (Program.FirstInstance)
                Program.RegisterSingleInstanceChannelAndController(Program.SendMailForm);

            this.lastPopup = this.LastSeen;

            //trayIcon.Icon = Properties.Resources.nomail;
            trayIcon.Icon = Properties.Resources.ResourceManager.GetObject(Properties.Settings.Default.Color + "2") as Icon;
            trayIcon.Text = "Initializing ...";
            trayIcon.Visible = Program.StayInTray;

        }



        private void PoupNewMail()
        {
            UpdateIconText(true);

            trayIcon.BalloonTipTitle = "You have new mail";
            trayIcon.BalloonTipText = "Count since last seen: " + this.lastSeenCount + "\r\nUnread count: " + this.fullcount;
            trayIcon.BalloonTipIcon = ToolTipIcon.Info;
            trayIcon.ShowBalloonTip(10000);
        }

        private void HiglightTrayIcon(bool p)
        {
            if (p)
                //trayIcon.Icon = Properties.Resources.unreadmail;
                trayIcon.Icon = Properties.Resources.ResourceManager.GetObject(Properties.Settings.Default.Color + "1") as Icon;
            else
                //trayIcon.Icon = Properties.Resources.nomail;
                trayIcon.Icon = Properties.Resources.ResourceManager.GetObject(Properties.Settings.Default.Color + "2") as Icon;
        }

        private void ClearUnreadMark()
        {
            this.LastSeen = this.lastPopup;
            this.lastSeenCount = 0;
            CleanSummaryItems();
            UpdateIconText(HasNetwork());
            HiglightTrayIcon(false);
        }

        private void UpdateIconText(bool hasNetwork)
        {
            string msg = "";
            if (!hasNetwork)
                msg += " Network disconnected\r\n";
            msg += " Last seen: " + this.lastSeenCount + " \r\n Unread count: " + this.fullcount + " ";
            trayIcon.Text = LimitLength(msg, 64 - 0 - 1, false);
        }


        static string LimitLength(string text, int length, bool appendSuffix)
        {
            if (appendSuffix && text.Length > length)
            {
                string ret = text.Substring(0, length - 4);
                return ret + " ...";
            }
            else
            {
                return text.Substring(0, Math.Min(text.Length, length));
            }
        }

        const int EMAIL_SUMMARY_MENU_INDEX = 0;
        void CheckMail()
        {
            if (!HasNetwork())
            {
                UpdateIconText(false);
                return;
            }

            try
            {
                trayIcon.Icon = Properties.Resources.checking;

                // Build and convert the authorization information
                // The variables account and password are strings with the GMail credentials
                StringBuilder sb = new StringBuilder(Program.OptionsForm.loginTextBox.Text);
                sb.Append(":");
                sb.Append(Program.OptionsForm.pwdTextBox.Text);
                Byte[] bytes = Encoding.ASCII.GetBytes(sb.ToString());

                // Create the request
                CookieContainer cookiecontainer = new CookieContainer();
                HttpWebRequest feedRequest = (HttpWebRequest)WebRequest.Create("https://mail.google.com/mail/feed/atom");
                // Google uses Basic Auth so we add this header to the request
                feedRequest.Headers.Add("Authorization", "Basic " +
                    Convert.ToBase64String(bytes));
                feedRequest.CookieContainer = cookiecontainer;
                // Get the response in the form of a stream
                HttpWebResponse response = (HttpWebResponse)feedRequest.GetResponse();
                // begin debug
                object o = response.Headers;
                CookieCollection cookies = response.Cookies;
                // end debug
                Stream feedStream = response.GetResponseStream();

                // We are going to use a DataSet and XmlReader to get at the contents of the Xml Response
                DataSet dsFeed = new DataSet();
                XmlReader feedReader = XmlReader.Create(feedStream);
                string s = feedReader.ReadString();
                dsFeed.ReadXml(feedReader);

                this.fullcount = int.Parse(dsFeed.Tables["feed"].Rows[0]["fullcount"] as string);
                //trayMenu.ShowImageMargin = false;
                CleanSummaryItems();
                trayMenu.AutoSize = true;
                trayMenu.SuspendLayout();
                foreach (ToolStripItem item in trayMenu.Items)
                {
                    if (item is PreviewMenuItem) continue;
                    item.AutoSize = true;
                }

                int previewWidth = 270;
                int lastseencount = 0;
                int menuitems = 0;
                if (dsFeed.Tables["author"] != null && dsFeed.Tables["entry"] != null)
                {
                    dsFeed.Tables["author"].PrimaryKey = new DataColumn[] { dsFeed.Tables["author"].Columns["entry_Id"] };
                    foreach (DataRow row in dsFeed.Tables["entry"].Rows)
                    {
                        DateTime modified = DateTime.Parse((row["issued"] as string).Replace("T24:", "T00:"));
                        if (modified > this.LastSeen)
                        {
                            lastseencount += 1;
                            if (lastseencount > 5) continue;

                            int entry_Id = (int)row["entry_Id"];
                            string mailid = "";
                            mailid = row["id"] as string;
                            mailid = mailid.Split(':')[2];
                            SummaryTag summaryTag = new SummaryTag();
                            summaryTag.Id = string.Format("{0:X}", Int64.Parse(mailid));
                            DataRow author = dsFeed.Tables["author"].Rows.Find(entry_Id);


                            string from = author["name"] as string;// +"<" + LimitLength(author["email"] as string, 36, true) + ">";
                            from += ": " + LimitLength(row["title"] as string, 50, true);
                            string summary = row["summary"] as string;

                            PreviewMenuItem preview = new PreviewMenuItem();
                            preview.AutoSize = false;
                            preview.Size = new Size(previewWidth, 48);
                            preview.Text = "";
                            preview.TextHeader = from;
                            preview.TextContent = summary;
                            preview.Font = new Font("Arial narrow", 9.0F);
                            preview.LineHeight = 15;
                            preview.Tag = summaryTag;
                            preview.Click += new EventHandler(openEmailToolStripMenuItem_Click);
                            trayMenu.Items.Insert(EMAIL_SUMMARY_MENU_INDEX + menuitems, preview);
                            menuitems += 1;

                            #region old title and summary menu items
                            //string from = author["name"] as string + "<" + LimitLength(author["email"] as string, 36, true) + ">";
                            //ToolStripMenuItem title = new ToolStripMenuItem(from + " " + LimitLength(row["title"] as string, 50, true));

                            ////title.AutoSize = false;
                            ////title.Size = new Size(152, 44);
                            ////title.Text = from + " " + LimitLength(row["title"] as string, 50, true)
                            ////    + "\r\n"
                            ////    + LimitLength(row["summary"] as string, 100, false)
                            ////    ;

                            //title.Font = new Font("Arial narrow", 9.0F);
                            //title.Tag = summaryTag;
                            //title.Click += new EventHandler(openEmailToolStripMenuItem_Click);
                            ////title.BackColor = SystemColors.ActiveCaptionText;
                            //trayMenu.Items.Insert(EMAIL_SUMMARY_MENU_INDEX + menuitems, title);
                            //menuitems += 1;

                            //ToolStripMenuItem summary = new ToolStripMenuItem(LimitLength(row["summary"] as string, 100, false));
                            //summary.Font = new Font("Arial narrow", 9.0F);
                            //summary.Tag = summaryTag;
                            //summary.Click += new EventHandler(openEmailToolStripMenuItem_Click);
                            ////summary.BackColor = SystemColors.ActiveCaptionText;
                            //summary.ForeColor = SystemColors.ControlDark;
                            //trayMenu.Items.Insert(EMAIL_SUMMARY_MENU_INDEX + menuitems, summary);
                            //menuitems += 1;

                            //if (mailsummary.Length >= 100)
                            //{
                            //    ToolStripMenuItem summary2 = new ToolStripMenuItem(mailsummary.Substring(100, Math.Min(200, mailsummary.Length)-100));
                            //    summary2.Font = new Font("Arial narrow", 9.0F);
                            //    summary2.Tag = SummaryTag;
                            //    summary2.Click += new EventHandler(openInboxToolStripMenuItem_Click);
                            //    summary2.BackColor = SystemColors.ActiveCaptionText;
                            //    summary2.ForeColor = SystemColors.ControlDark;
                            //    trayMenu.Items.Insert(EMAIL_SUMMARY_MENU_INDEX + menuitems, summary2);
                            //    menuitems += 1;
                            //}
                            #endregion
                        }
                    }
                }
                if (lastseencount > 0)
                {
                    trayMenu.Items.Remove(unreadMailSummaryToolStripMenuItem);
                    trayMenu.Items.Insert(0, unreadMailSummaryToolStripMenuItem);
                    trayMenu.ResumeLayout(true);
                    trayMenu.SuspendLayout();
                    Size bounds = trayMenu.Size;
                    trayMenu.AutoSize = false;
                    int menuWith = previewWidth + trayMenu.Padding.Right + trayMenu.Margin.Right;
                    trayMenu.Size = new Size(menuWith, bounds.Height);
                    int itemWidth = trayMenu.Size.Width - trayMenu.Padding.Right - trayMenu.Margin.Right;
                    foreach (ToolStripItem item in trayMenu.Items)
                    {
                        if (item is PreviewMenuItem) continue;
                        Size tmp = item.Size;
                        item.AutoSize = false;
                        item.Size = new Size(itemWidth, tmp.Height);
                    }
                    trayMenu.ResumeLayout(false);
                }
                else
                {
                    trayMenu.Items.Remove(unreadMailSummaryToolStripMenuItem);
                    trayMenu.ResumeLayout(true);
                }

                DateTime mostRecentEntryIssued = this.lastPopup;
                if (dsFeed.Tables["entry"]!=null && dsFeed.Tables["entry"].Rows.Count > 0)
                    mostRecentEntryIssued = DateTime.Parse((dsFeed.Tables["entry"].Rows[0]["issued"] as string).Replace("T24:", "T00:"));

                UpdateIconText(true);
                HiglightTrayIcon(mostRecentEntryIssued > this.LastSeen && lastseencount > 0);
                this.lastSeenCount = lastseencount;
                if (mostRecentEntryIssued > this.lastPopup)
                {
                    PoupNewMail();
                    this.lastPopup = mostRecentEntryIssued;
                }
                this.lastError = "";
            }
            catch (Exception ex)
            {
                Exception baseex = ex.GetBaseException();
                if (this.lastError == baseex.Message)
                    return; // We already shown this message.
                trayIcon.BalloonTipTitle = "Error";
                this.lastError = baseex.Message;
                trayIcon.BalloonTipText = baseex.Message;
                trayIcon.Text = "\r\n " + LimitLength(baseex.Message, 64 - 6 - 1, false) + " \r\n";
                //trayIcon.Icon = Properties.Resources.error;
                trayIcon.Icon = Properties.Resources.ResourceManager.GetObject(Properties.Settings.Default.Color + "3") as Icon;
                trayIcon.BalloonTipIcon = ToolTipIcon.Error;
                trayIcon.ShowBalloonTip(10000);
            }
        }
        string lastError = "";

        //static object SummaryTag = new int();
        class SummaryTag
        {
            public string Id;
        }

        private void CleanSummaryItems()
        {
            trayMenu.Items.Remove(unreadMailSummaryToolStripMenuItem);
            for (int i = trayMenu.Items.Count - 1; i >= 0; i--)
            {
                ToolStripItem menu = trayMenu.Items[i] as ToolStripItem;
                if (menu != null && menu.Tag is SummaryTag)
                    trayMenu.Items.Remove(menu);
            }
        }

        private void OpenInbox()
        {
            string inbox = "https://mail.google.com/mail";
            string url = BuildAuthUrl() + inbox;

            ChooseBrowser browser = Program.OptionsForm.browserComboBox.SelectedItem as ChooseBrowser;
            string option = "";
            if (browser.SupportsProfiles && Program.OptionsForm.profileTextBox.Text != "<Default>")
                option = string.Format(browser.ProfileOption, Program.OptionsForm.profileTextBox.Text);

            if (browser.IsDefault)
                Process.Start(url);
            else
                Process.Start(browser.ApplicationPath, option + " " + url);
        }

        private void OpenEmail(string id)
        {
            string email = "https://mail.google.com/mail/#inbox/"+ id;
            string url = BuildAuthUrl() + email;

            ChooseBrowser browser = Program.OptionsForm.browserComboBox.SelectedItem as ChooseBrowser;
            if (browser.IsDefault)
                Process.Start(url);
            else
                Process.Start(browser.ApplicationPath, url);
        }

        private string BuildAuthUrl()
        {
            string login = Program.OptionsForm.loginTextBox.Text;
            string pwd = Program.OptionsForm.pwdTextBox.Text;

            // Build and convert the POST body
            string postText = "";
            postText += "accountType=GOOGLE";
            postText += "&";
            postText += "Email=" + login;
            postText += "&";
            postText += "Passwd=" + pwd;
            postText += "&";
            postText += "service=mail";
            postText += "&";
            postText += "source=googletalk";
            byte[] postData = Encoding.ASCII.GetBytes(postText);

            // Create the request
            HttpWebRequest authRequest = (HttpWebRequest)WebRequest.Create("https://www.google.com/accounts/ClientLogin");
            authRequest.Method = "POST";
            authRequest.ContentType = "application/x-www-form-urlencoded";
            authRequest.ContentLength = postData.Length;
            Stream requestStream = authRequest.GetRequestStream();
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();

            // Get the response in the form of a stream
            HttpWebResponse response = (HttpWebResponse)authRequest.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                Stream responseStream = response.GetResponseStream();
                StreamReader responseReader = new StreamReader(responseStream, Encoding.ASCII);
                string responseText = responseReader.ReadToEnd();
                response.Close();
                string[] values = responseText.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                string auth = "";
                string sid = "";
                string lsid = "";
                foreach (string value in values)
                {
                    if (value.StartsWith("Auth="))
                        auth = value.Substring(5);
                    else if (value.StartsWith("SID="))
                        sid = value.Substring(4);
                    else if (value.StartsWith("LSID="))
                        lsid = value.Substring(5);
                }
                //query = "SID=#{@pre_tokens['SID']}&LSID=#{@pre_tokens['LSID']}&service=gaia&Session=true"


                postText = "";
                postText += "SID=" + sid;
                postText += "&";
                postText += "LSID=" + lsid;
                postText += "&";
                postText += "service=gaia&Session=true";
                postData = Encoding.ASCII.GetBytes(postText);

                // Create the request
                HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create("https://www.google.com/accounts/IssueAuthToken");
                tokenRequest.Method = "POST";
                tokenRequest.ContentType = "application/x-www-form-urlencoded";
                tokenRequest.ContentLength = postData.Length;
                requestStream = tokenRequest.GetRequestStream();
                requestStream.Write(postData, 0, postData.Length);
                requestStream.Close();

                string tokenText = "";
                response = (HttpWebResponse)tokenRequest.GetResponse();
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    responseStream = response.GetResponseStream();
                    responseReader = new StreamReader(responseStream, Encoding.ASCII);
                    tokenText = responseReader.ReadToEnd();
                    response.Close();
                }
                else
                    response.Close();


                string url = "https://www.google.com/accounts/TokenAuth?auth=";
                url += tokenText.TrimEnd();
                url += "&service=mail&source=googletalk";
                url += "&continue=";
                return url;
            }
            else
                response.Close();

            throw new SystemException("Auth url cannot be build");
        }

        bool HasNetwork()
        {
            IPAddress[] addrs = Dns.GetHostAddresses(Dns.GetHostName());
            bool found = false;
            foreach (IPAddress addr in addrs)
            {
                string ip = addr.ToString();
                if (ip.StartsWith("5."))
                    continue;
                found = true;
            }
            return found;
        }

        private void clearUnreadMarkToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ClearUnreadMark();
        }

        private void openInboxToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenInbox();
        }

        private void openEmailToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripItem menu = sender as ToolStripItem;
            string id = (menu.Tag as SummaryTag).Id;
            OpenEmail(id);
        }

        private void checkMailNowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CheckMail();
        }

        private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (DialogResult.OK == Program.OptionsForm.ShowDialog())
                CheckMail();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            About.Default.ShowDialog();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void trayIcon_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ClearUnreadMark();
                CheckMail();
            }
        }

        private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            OpenInbox();
        }

        private void trayMenu_Opening(object sender, CancelEventArgs e)
        {
            lastSeenCountMenuItem.Text = "Last seen count: " + this.lastSeenCount + " / Unread count: " + this.fullcount;
            if (Program.OptionsForm.loginTextBox.Text.Trim() != "")
                exitToolStripMenuItem.Text = "Exit  (" + Program.OptionsForm.loginTextBox.Text + ")";
            else
                exitToolStripMenuItem.Text = "Exit";
        }
    }
}